<template>
  <div>
    <el-upload
      ref="upFileImg"
      :action="action"
      :show-file-list="false"
      :headers="header"
      :disabled="isloading || readonly"
      :auto-upload="false"
      :before-upload="checkFile"
      :multiple="multiple"
      :accept="accept"
      :http-request="sendFile"
      :on-change="fileChange"
    >
      <slot v-if="files.length > 0 && isShowFiles" name="fileList" :files="files">
        <ul class="el-upload-list el-upload-list--picture-card">
          <li
            v-for="file in files"
            :key="file.FileId"
            :class="'el-upload-list__item ' + (file.status == 'success' ? 'is-success': '')"
          >
            <icon v-if="file.type === 'file'" class="icon" :icon="file.icon" />
            <icon v-else-if="file.type === 'video' && file.status == 'ready'" class="icon" :icon="file.icon" />
            <img
              v-else-if="file.type === 'video' && file.status == 'success'"
              :src="file.thumbnai | imageUri"
              :alt="file.FileName"
              class="el-upload-list__item-thumbnail"
            >
            <img
              v-else
              :src="file.FileUri | imageUri"
              :alt="file.FileName"
              class="el-upload-list__item-thumbnail"
            >
            <el-progress v-if="file.status == 'ready'" type="circle" :percentage="file.percentage" text-color="#1890ff" />
            <label class="el-upload-list__item-status-label">
              <i
                class="el-icon-upload-success el-icon-check"
              /></label>
            <span class="el-upload-list__item-actions">
              <span v-if="readonly == false" class="el-upload-list__item-delete">
                <i class="el-icon-delete" @click="(e)=>dropFile(file.FileId,e)" />
              </span>
              <span
                v-if="allowAmplify && file.status == 'success'"
                class="el-upload-list__item-delete"
              >
                <i class="el-icon-zoom-in" @click="(e)=> openFile(file, e)" />
              </span>
              <span v-if="isOrderBy && file.status == 'success'" class="el-upload-list__item-delete">
                <i class="el-icon-top" @click="(e)=> setSort(file, 'up', e)" />
              </span>
              <span v-if="isOrderBy && file.status == 'success'" class="el-upload-list__item-delete">
                <i class="el-icon-bottom" @click="(e)=> setSort(file, 'bottom', e)" />
              </span>
            </span>
          </li>
        </ul>
      </slot>
      <slot :fileNum="files.length" name="trigger">
        <i v-if="upFilelimit != files.length && readonly == false" v-loading="isloading" class="el-icon-plus uploader-icon" />
      </slot>
      <div v-if="isShowTip" slot="tip">
        <slot
          name="upTip"
          :show="imgLimit ? imgLimit.Show : null"
          :UpShow="upConfig.UpShow"
          :error="error"
        >
          <div class="el-upload__tip">
            <span v-if="error" style="color: red">{{ error }}</span>
            <template v-else>
              <div style="height: 30px; line-height: 30px">
                {{ upConfig.UpShow }}
              </div>
              <div
                v-if="imgLimit && imgLimit.Show"
                style="height: 30px; line-height: 30px"
              >
                {{ imgLimit.Show }}
              </div>
            </template>
          </div>
        </slot>
      </div>
    </el-upload>
    <el-dialog width="90%" :visible.sync="amplifyVisible" :destroy-on-close="true" :title="chioseFile.FileName" @close="close">
      <div style="width: 100%; overflow: auto;">
        <img v-if="chioseFile.type == 'img'" style="max-width: 100%;" :src="chioseFile.FileUri | imageUri" alt="">
        <video v-else-if="chioseFile.type == 'video'" ref="videoCon" controls="" autoplay="false" name="media">
          <source :src="chioseFile.FileUri | imageUri" type="video/mp4">
        </video>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import * as fileApi from '@/api/base/file'
import * as upTools from '@/utils/fileUpTools'
import icon from '../tools/icon.vue'
export default {
  components: { icon },
  props: {
    fileKey: {
      type: String,
      default: null
    },
    tag: {
      type: String,
      default: null
    },
    linkBizPk: {
      type: String,
      default: null
    },
    fileUri: {
      type: Array,
      default: null
    },
    multiple: {
      type: Boolean,
      default: false
    },
    upFilelimit: {
      type: Number,
      default: 1
    },
    value: {
      type: Array,
      default: null
    },
    readonly: {
      type: Boolean,
      default: false
    },
    allowAmplify: {
      type: Boolean,
      default: true
    },
    isOrderBy: {
      type: Boolean,
      default: false
    },
    isShowTip: {
      type: Boolean,
      default: true
    },
    isShowFiles: {
      type: Boolean,
      default: true
    },
    isSave: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      action: null,
      error: null,
      isloading: false,
      isInit: false,
      upConfig: {},
      md5: null,
      files: [],
      amplifyVisible: false,
      oldPk: null,
      accept: null,
      chioseFile: {},
      imgLimit: null,
      header: {
        accreditId: this.$store.getters.token
      }
    }
  },
  watch: {
    fileKey: {
      handler(val) {
        if (val && this.isInit === false) {
          this.isInit = true
          this.reset()
        }
      },
      immediate: true
    },
    linkBizPk: {
      handler(val) {
        if (this.fileKey && val !== this.oldPk) {
          this.oldPk = val
          this.reset()
        }
      },
      immediate: false
    },
    isSave: {
      handler(val) {
        if (this.fileKey != null && this.linkBizPk != null) {
          this.resetUri()
        }
      },
      immediate: true
    },
    imgSet: {
      handler(val) {
        this.imgLimit = val
      },
      immediate: true
    },
    value: {
      handler(val) {
        if (
          this.linkBizPk == null &&
          (val == null || val.length === 0) &&
          this.files.length !== 0
        ) {
          this.files = []
        }
      },
      immediate: false
    }
  },
  methods: {
    close() {
      if (this.chioseFile.type === 'video') {
        this.$refs.videoCon.pause()
        this.chioseFile = {}
      }
    },
    dropFile(fileId, e) {
      e.stopPropagation()
      this.isloading = true
      const index = this.files.findIndex((c) => c.FileId === fileId)
      if (index !== -1) {
        const file = this.files[index]
        if (file.status === 'ready') {
          file.isCancel = true
        }
        this.files.splice(index, 1)
        this.changeEvent('change')
      }
      this.isloading = false
    },
    dropTempFile(file) {
      const index = this.files.findIndex((c) => c.FileId === file.uid)
      if (index !== -1) {
        this.files.splice(index, 1)
      }
    },
    addTempFile(file) {
      const item = {
        FileId: file.uid,
        FileName: file.name,
        percentage: 0,
        status: 'ready'
      }
      upTools.initFile(item, file)
      this.files.push(item)
      return item
    },
    openFile(file, e) {
      e.stopPropagation()
      if (file.type === 'img' || file.type === 'video') {
        this.chioseFile = file
        this.amplifyVisible = true
        return
      } else if (file.ext === '.pdf') {
        const uri = file.FileUri + '?accreditId=' + this.$store.getters.token
        window.open(uri)
        return
      }
      const uri = file.FileUri + '?accreditId=' + this.$store.getters.token + '&isDown=true'
      window.open(uri)
    },
    async sendFile(e) {
      if (this.files.findIndex((c) => c.FileId === e.file.uid) !== -1) {
        return
      }
      const file = this.addTempFile(e.file)
      this.isloading = false
      if (e.file.size >= this.upConfig.ZoneSize) {
        this.sendBlock(e, file)
      } else {
        this.sendSingleFile(e, file)
      }
    },
    async sendBlock(e, file) {
      file.isCancel = false
      const res = await upTools.blockUp({
        DirKey: this.fileKey,
        LinkBizPk: this.linkBizPk,
        Tag: this.tag
      }, this.md5, e.file, (val) => {
        if (val < 0) {
          file.percentage = 0
          return
        }
        file.percentage = val
      }, file)
      this.$refs.upFileImg.abort(e.file)
      if (res != null) {
        this.upComplate(res, e.file)
      }
    },
    async sendSingleFile(e, file) {
      const res = await fileApi.upFile(this.action, e.file, (val) => {
        file.percentage = val
      })
      this.$refs.upFileImg.abort(e.file)
      this.upComplate(res, e.file)
    },
    upComplate(res, file) {
      this.dropTempFile(file)
      res.status = 'success'
      this.addFile(res)
    },
    addFile(file) {
      upTools.initFile(file)
      this.files.push(file)
      this.changeEvent('change')
    },
    upFail(error) {
      this.error = error
      if (this.isShowTip === false) {
        this.$emit('error', error)
      }
    },
    setSort(file, type, e) {
      e.stopPropagation()
      const index = this.files.findIndex((c) => c.FileId === file.FileId)
      if (type === 'up') {
        if (index <= 0) {
          return
        }
        const list = this.files.concat()
        const other = list[index]
        list[index] = list[index - 1]
        list[index - 1] = other
        this.files = list
      } else {
        if (index >= this.files.length - 1) {
          return
        }
        const list = this.files.concat()
        const other = list[index]
        list[index] = list[index + 1]
        list[index + 1] = other
        this.files = list
      }
      this.saveSort()
    },
    async saveSort() {
      const sort = {}
      for (let i = 0; i < this.files.length; i++) {
        sort[this.files[i].FileId] = i
      }
      await fileApi.saveSort(sort)
    },
    changeEvent(eventName) {
      const fileId = []
      const src = []
      this.files.forEach((c) => {
        fileId.push(c.FileId)
        src.push(c.FileUri)
      })
      this.$emit('input', fileId)
      this.$emit('update:fileUri', src)
      this.$emit(eventName, fileId, this.files)
    },
    resetUri() {
      this.action = fileApi.getfileUpUri(this.fileKey)
      if (this.linkBizPk != null && this.linkBizPk !== '') {
        this.action =
          this.action +
          '?linkBizPk=' +
          this.linkBizPk +
          '&tag=' +
          (this.tag == null ? '' : this.tag) +
          '&isSave=' +
          (this.isSave ? 'true' : 'false')
      }
    },
    async reset() {
      this.amplifyVisible = false
      this.resetUri()
      const config = await fileApi.getUpConfig(
        this.fileKey,
        this.linkBizPk,
        this.tag
      )
      if (config.Extension == null) {
        config.Extension = []
      }
      if (config.UpImgSet !== null && this.imgSet == null) {
        this.imgLimit = config.UpImgSet
      }
      this.accept = config.Extension.join(',')
      this.upConfig = config
      if (config.Files != null) {
        config.Files.forEach(a => {
          a.status = 'success'
          upTools.initFile(a)
        })
        this.files = config.Files
      } else {
        this.files = []
      }
      this.changeEvent('load')
    },
    checkFile(file) {
      this.error = null
      const type = upTools.getFileType(file.type, file.name)
      if (type == null) {
        this.error = '暂不支持该类型的文件!'
        return false
      } else if (!this.checkUpFile(file, type)) {
        return false
      } else {
        return true
      }
    },
    async fileChange(file, fileList) {
      if (this.error != null || file.status !== 'ready') {
        return
      }
      this.isloading = true
      const type = upTools.getFileType(file.type, file.name)
      if (upTools.checkIsImg(type)) {
        const res = await upTools.checkImg(file.raw, this.imgLimit)
        if (!res) {
          this.cancelUp(file, fileList)
          this.upFail(this.imgLimit.Show)
          return
        }
      }
      const md5 = await upTools.loadMD5(file.raw)
      const res = await this.preFileUp(md5, file)
      this.md5 = md5
      if (res) {
        this.$refs.upFileImg.submit()
      } else {
        this.cancelUp(file, fileList)
      }
    },
    cancelUp(file, fileList) {
      this.$refs.upFileImg.abort(file)
      const index = fileList.findIndex((c) => c.uid === file.uid)
      if (index > 0) {
        fileList.splice(index, 1)
      }
      this.isloading = false
    },
    async preFileUp(md5, file) {
      const res = await fileApi.preUpFile(
        {
          FileMd5: md5,
          FileName: file.name,
          LinkBizPk: this.linkBizPk,
          Tag: this.tag,
          IsSave: this.isSave
        },
        this.fileKey
      )
      if (res.IsUp) {
        res.status = 'success'
        this.addFile(res)
        return false
      } else {
        return true
      }
    },
    checkUpFile(file, type) {
      if (this.upConfig == null) {
        return false
      } else if (
        this.upConfig.Extension.length !== 0 &&
        !this.upConfig.Extension.includes(type)
      ) {
        this.error = '暂不支持' + type + '类型的文件!'
        return false
      }
      if (this.upConfig.UpFileSize && file.size > this.upConfig.UpFileSize) {
        this.error =
          '上传文件大小不能超过 ' +
          Math.round((this.upConfig.UpFileSize / 1024 / 1024) * 100) / 100 +
          'MB'
        return false
      }
      return true
    }
  }
}
</script>
<style scoped>
.uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 120px;
  height: 120px;
  line-height: 120px;
  text-align: center;
  border: 1px;
  border-color: #8c939d;
  border-style: dashed;
}
.el-upload-list__item {
  line-height: 148px;
  text-align: center;
}
.el-upload-list--picture-card {
  padding-left: 20px;
}
.uploader-img {
  height: 120px;
}
.el-upload-list--picture-card .icon {
  font-size: 40px;
}
</style>
<style>
.el-upload-list .el-progress__text {
  color: #ff6d6d;
  font-weight: 700;
  font-size: 24px !important;
}
.el-loading-spinner {
  top: 25% !important;
}
</style>
